ReactのMain Concept:12. Thinking In React
Reactは巨大で早いWebアプリをJavaScriptで作る(Reactチームの主張する)方法
FacebookとInstagramを作っているときにうまくスケールした
Reactのいいところの一つは、どのようにアプリを制作すればよいかの考え方を提供するところです
本章では、検索可能な商品データテーブルをReactでつくっていく思考プロセスを説明します
Start With A Mock
JSON APIとmockがすでにあると仮定する
Step 1: Break The UI Into A Component Hierarchy
はじめにあなたがやりたくなることは、モックのすべてのコンポーネント(とサブコンポーネント)を四角で囲んで、名前を与えることです
デザイナーと仕事をしていたらたぶんもうやっています(だから話そう!)
彼らのPhotoshopのレイヤー名はReact componentの名前になるかもしれません
問題
なにがコンポーネントになるべきなのかわからない
対策
オブジェクトやfunctionを作るのを決めるときにやることと同じテクニックがつかえます
componentが肥大化し続けたら、分割する
モックをcomponentにしていこう
JSONデータモデルをユーザに見せることがよくあるなら、そのデータモデルは正しく作られていて、UI(componentの構造)にいい感じにmapされていることに気づくだろう
なぜなら、UIとデータモデルは同じ「情報の構造」で結びつきがちだから
ということは、UIをcomponentに分割するのはしばしば自明で、データモデルの一部分を正しく表現するコンポーネントに分割するだけ!
実際に分割してみる
https://gyazo.com/648edd52835f9794c60ad1a967caf803
このように5つに分割できる(このあたりはしょってる。原文をみて)
議論
ProductTable(緑)にName/Priceのようなヘッダが入るかどうかは好みによる
ここではProducteTableの描画する責務があるデータコレクションの一部とみなした
だけど、ヘッダーがもっと複雑になってきたら(ソートしたくなるかも)、ProductTableHeader componentに分割するのが適切に感じるかも
上の図をもとに、componentの階層をつくっていこう
ここは機械的にできる。囲われているものを親に持つ階層構造にすればいい
FilterableProducteTable
SearchBar
ProductTable
ProductCategoryRow
ProductRow
Step 2: Build A Static Version in React
階層構造ができたので、実装していく
まずは、データモデルを受け取ってUIを描画する(非インタラクティブな)バージョンを作るのが簡単
static/intaractiveは別工程として分割して作っていくのがよい
static versionはコーディングが大変だけど、考えることがない
これをインタラクティブにしようとすると、めっちゃ考えることがあり、もっとコーディングが大変
このことは、やっていくうちに理解できるよ
データモデルをレンダリングするstatic versionのアプリをつくるためには、こんなcomponentが欲しくなる
「他のコンポーネントを再利用して、propsをつかってデータを渡す」component
なお、propsは親から子供にデータを渡す方法
もしstateの概念に慣れ親しんでいるなら、static versionのbuildにはstateを一切使わないこと
stateはデータが時々刻々変わっていくinteractivityだけのためのものだから、static versionには必要ない
top downでもbottom upにでも作っていける
階層の高いところのcomponent(例えばオレンジ)からはじめてもいいし、低いところ(赤)からはじめてもいい
top downかbottom upか
単純な例では、top-downに作るほうが普通は簡単
大きなプロジェクトでは、ボトムアップに作りながらテストを書いていくのが簡単
この手順を終えると、データモデルを描画する再利用可能なコンポーネントのライブラリができる
static versionなので、componentはrender()メソッドだけをもっている
階層のrootのcomponentはpropとしてデータモデルを受け取る
もし背後のデータモデルを変更したい場合には、ReactDom.render()を再度呼ぶことでUIは変更される
こうすると、どのようにUIがアップデートされるのか、どこで変更が行われるのかがわかる
ややこしいことはしていないから
A Brief Interlude: Props vs State
Reactの"model"データには二種類ある
props
state
この2つを区別して理解するのは重要
Step 3: Identify The Minimal (but complete) Representation Of UI State
インタラクティブにしていくkadoyau.icon
UIをインタラクティブにしたいなら、背後のデータモデルを変更するためのトリガーがほしいときがある
Reactではstateを使うと簡単に作れる
正しくアプリを作るために、まずアプリが必要としているmutableなstateの最小限の集合を考える必要がある
ここでのキーとなる考え方はDRYだ。アプリケーションが必要とする状態の最小限の表現を明らかにして、必要なすべてをオンデマンドに計算しよう 例えば、もしTODOリストをつくっていたとする。TODOのアイテムの配列だけを保持して、カウントについての別の状態変数をもってはいけない。そのかわり、もしTODOの総数を描画したいなら、単純にTODO配列の長さを取ろう
例のアプリのデータのすべてのピースについて考えていこう。次のとおり
Productsのオリジナルなリスト
ユーザが入力した検索テキスト
チェックボックスの値
フィルターされたProducts
それぞれについて考えていき、どれが状態なのか明らかにしていこう
単純に3つの質問を各データのピースについて考えよう
stateの見分け方
1. それは親からpropsで渡されたもの?もしそうなら、たぶんstateではない
2. 時間がたっても不変の値?もしそうなら、たぶんstateではない
3. それはcomponent中の他のstateやpropsから計算できる?もしそうなら、それはstateではない
それぞれについて考えてみると
Productsのオリジナルなリスト
stateではない
理由:productsのオリジナルなリストはpropsで渡される
ユーザが入力した検索テキスト および チェックボックスの値
2つともstateっぽい
理由:時間で変化するし、他の値から算出できないから
フィルターされたProducts
stateではない
理由:他の3つから算出できる
結局、例のアプリのステートは次の2つになる
ユーザが入力した検索テキスト
チェックボックスの値
Step 4: Identify Where Your State Should Live
アプリの最小のstateが明らかになったので、どのcomponentがこれらのstateを変化させるのか、または所持するかを明らかにしていこう
覚えておいて:Reactはcomponent階層を下る1方向データフローそのものです。どのcomopnentが何のstateを所持すべきかがすぐに明らかにならないかもしれません。ここがReact初心者には一番理解がむずかしくなりがち。だから理解のために次のstepに従ってください
アプリケーションの各stateについて
そのstateに基づいてなにかを描画するすべてのコンポーネントを明確にする
stateから算出したものに基づいていた場合もこれに該当するかもkadoyau.icon
共通のownerコンポーネントを探す
単一のコンポーネントで、そのステートを必要としているコンポーネントすべてよりも上層にあるもの
code:こんなんになればOK
共通の親component
必要としてるcomponent
必要としてるcomponent
共通のownerかもっと上の階層にいる他のcomponentが自分のstateを所持するべき
もしstateを所持する意味のあるcomponentを見つけられなかった場合、そのstateを所持するだけの単純なcomponentを新しく作成し、共通のowner ocmpponentのどこかの上の階層に追加します
意味のあるcomponentを見つけられないパターンってどういうときだろうkadoyau.icon
このアプリケーションにこの戦略を適用してみよう
ユーザが入力した検索テキスト
チェックボックスの値
をどこが持つのかを決めるのが目標だ
https://gyazo.com/648edd52835f9794c60ad1a967caf803
入力値は両方Searchbarが持つと思うんだけど、stateを入力するだけでなく、stateを利用するコンポーネントについても検討していく必要があることに注意kadoyau.icon
ProductTable(緑)はstateに基づいたProductリストをフィルターするために必要だ
さらに、検索テキストとチェックされた状態を表示するためにSerchbar(青)が必要だ
これらの共通のowner componentはFilterableProductTable(黄色)だ
フィルタされたテキストとチェックされた値がFilterableProductTableにいるのは概念的に意味がある
やったぜ。結局ぼくらのstateはFilterableProductTableにもてばいいことがわかった。最初にインスタンスプロパティをFilterableProductTableのコンストラクタに追加しよう。これでアプリケーションの初期状態を反映することができる
次に、filterTextとinStockOnlyをProductTableと SearchBarにpropとして渡す
最後に、これらの propsを ProductTableの行をフィルタするのに使って、SearchBarのformフィールドの値をセットする
どのようにアプリが振る舞うか見てみよう。
filterTextをballにセットしてアプリをリフレッシュしてみよう
data tableが正しく更新されるだろう
Step 5: Add Inverse Data Flow
ここまで、propsとstateを上層からおろしていく関数として、正しく描画するアプリを構築できた
他の方法でデータを流せるようにしてみよう
目標:下層のform componestsはFilterableProductTableにあるstateを更新したい
Reactはあなたのプログラムがどのように動いているのか理解するのを簡単にするために、このデータフローを明示的にすることができます。しかし、これは典型的なtwo-way data bindingよりもすこしtype量を要求します
現状の例においてboxにチェックを入れたり入力をしたりしても、Reactはあなたの入力を無視する
これは意図したもので、inputのvaluepropがFilterableProductTableから渡されたstateと一致するようになっている
何がしたいのか考えてみましょう
ユーザがformを変更したときにはいつも、stateにその値を反映するということを確実に行いたい
componentsは自分のstateしかupdateできないので、FilterableProductTableはSearchBarに、stateが更新されたときに発火するcallbackを渡します
入力のonChangeイベントを、入力を通知するために使えます
FilterableProductTableから渡されたcallbackはsetState()を呼んで、appが更新されます
複雑そうに聴こえても、実際は単にすこしのコードをたすだけです。これは、アプリをどのようにデータが通り抜けていくかを明確にします
And That’s It
componentとappをReactでどのように組むかのアイデアを与えられたかな?
いままでやってきたよりもtype量が多いと思うけど、次のことを覚えておいてほしい
codeは書くよりよむほうが多い
モジュール化されて明示的なコードを詠むのは簡単
componentの巨大なライブラリを作成し始めたら、この事のありがたみがわかるだろうし、再利用可能なコードによって、codeを書く行数が減っていきます